package org.convallaria.system.biz.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.infrastruct.ce.annotation.CacheEvictAll;
import org.convallaria.infrastruct.ce.annotation.CacheRefresh;
import org.convallaria.infrastruct.ce.annotation.CacheWarmup;
import org.convallaria.infrastruct.ce.util.CacheUtils;
import org.convallaria.infrastruct.ce.util.RedisCacheUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 缓存验证服务
 * 用于验证ce模块的各种缓存功能
 * 
 * @author gjh
 * @since 2024-09-24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheValidationService {

    private final CacheUtils cacheUtils;
    private final RedisCacheUtils redisCacheUtils;
    
    // 用于验证缓存命中率的计数器
    private final AtomicLong cacheHitCount = new AtomicLong(0);
    private final AtomicLong cacheMissCount = new AtomicLong(0);

    /**
     * 基本缓存功能验证
     * 测试Spring Cache的基本功能，包括缓存存储和获取
     */
    @Cacheable(value = "user-cache", key = "#id")
    public UserInfo getUserById(Long id) {
        log.info("从数据库获取用户信息: {}", id);
        cacheMissCount.incrementAndGet();
        
        // 模拟数据库查询延迟
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return UserInfo.builder()
                .id(id)
                .name("用户" + id)
                .email("user" + id + "@example.com")
                .phone("1380000" + String.format("%04d", id % 10000))
                .build();
    }

    /**
     * 条件缓存验证
     */
    @Cacheable(value = "user-cache", key = "#id", condition = "#id > 0")
    public UserInfo getUserByIdWithCondition(Long id) {
        log.info("从数据库获取用户信息（条件缓存）: {}", id);
        cacheMissCount.incrementAndGet();
        
        return UserInfo.builder()
                .id(id)
                .name("用户" + id)
                .email("user" + id + "@example.com")
                .phone("1380000" + String.format("%04d", id % 10000))
                .build();
    }

    /**
     * 缓存更新验证
     */
    @CacheEvict(value = "user-cache", key = "#user.id")
    public void updateUser(UserInfo user) {
        log.info("更新用户信息: {}", user.getId());
        // 模拟数据库更新
    }

    /**
     * 批量清除缓存验证
     */
    @CacheEvictAll(value = {"user-cache", "config-cache"})
    public void clearAllUserCache() {
        log.info("清除所有用户相关缓存");
    }

    /**
     * 缓存刷新验证
     */
    @CacheRefresh(value = "user-cache", async = true)
    public void refreshUserCache() {
        log.info("刷新用户缓存");
    }

    /**
     * 缓存预热验证
     */
    @CacheWarmup(value = "user-cache", async = true, order = 1)
    public void warmupUserCache() {
        log.info("预热用户缓存");
        // 预热常用数据
        for (long i = 1; i <= 10; i++) {
            getUserById(i);
        }
    }

    /**
     * 使用CacheUtils的验证
     */
    public UserInfo getUserWithUtils(Long id) {
        String key = cacheUtils.generateKey("getUserById", id);
        
        return cacheUtils.getOrCompute("user-cache", key, UserInfo.class, () -> {
            log.info("从数据库获取用户信息（使用CacheUtils）: {}", id);
            cacheMissCount.incrementAndGet();
            return UserInfo.builder()
                    .id(id)
                    .name("用户" + id)
                    .email("user" + id + "@example.com")
                    .phone("1380000" + String.format("%04d", id % 10000))
                    .build();
        });
    }

    /**
     * 异步缓存操作验证
     */
    public CompletableFuture<UserInfo> getUserAsync(Long id) {
        return CompletableFuture.supplyAsync(() -> {
            log.info("异步获取用户信息: {}", id);
            return getUserById(id);
        });
    }

    /**
     * Redis缓存工具验证
     */
    public void testRedisCacheUtils(Long id) {
        String key = "user:redis:" + id;
        UserInfo user = UserInfo.builder()
                .id(id)
                .name("Redis用户" + id)
                .email("redis.user" + id + "@example.com")
                .phone("1380000" + String.format("%04d", id % 10000))
                .build();
        
        // 设置缓存
        redisCacheUtils.set(key, user, Duration.ofHours(1));
        log.info("设置Redis缓存: {}", key);
        
        // 获取缓存
        UserInfo cachedUser = redisCacheUtils.get(key, UserInfo.class);
        log.info("获取Redis缓存: {} -> {}", key, cachedUser);
        
        // 检查缓存是否存在
        boolean exists = redisCacheUtils.exists(key);
        log.info("Redis缓存是否存在: {} -> {}", key, exists);
        
        // 设置过期时间
        redisCacheUtils.expire(key, Duration.ofMinutes(30));
        log.info("设置Redis缓存过期时间: {}", key);
        
        // 获取剩余过期时间
        long expire = redisCacheUtils.getExpire(key);
        log.info("Redis缓存剩余过期时间: {} -> {}秒", key, expire);
    }

    /**
     * 缓存性能测试
     */
    public void performanceTest(int iterations) {
        log.info("开始缓存性能测试，迭代次数: {}", iterations);
        
        long startTime = System.currentTimeMillis();
        
        // 第一次调用（缓存未命中）
        for (int i = 1; i <= iterations; i++) {
            getUserById((long) i);
        }
        
        long firstCallTime = System.currentTimeMillis();
        log.info("第一次调用耗时: {}ms", firstCallTime - startTime);
        
        // 第二次调用（缓存命中）
        for (int i = 1; i <= iterations; i++) {
            getUserById((long) i);
        }
        
        long secondCallTime = System.currentTimeMillis();
        log.info("第二次调用耗时: {}ms", secondCallTime - firstCallTime);
        
        // 计算性能提升
        double performanceImprovement = (double) (firstCallTime - startTime) / (secondCallTime - firstCallTime);
        log.info("性能提升倍数: {:.2f}x", performanceImprovement);
        
        // 计算缓存命中率
        long totalCalls = iterations * 2;
        long hits = totalCalls - cacheMissCount.get();
        double hitRatio = (double) hits / totalCalls;
        log.info("缓存命中率: {:.2f}%", hitRatio * 100);
    }

    /**
     * 缓存统计信息
     */
    public CacheStatistics getCacheStatistics() {
        return CacheStatistics.builder()
                .hitCount(cacheHitCount.get())
                .missCount(cacheMissCount.get())
                .totalCount(cacheHitCount.get() + cacheMissCount.get())
                .hitRatio(cacheHitCount.get() + cacheMissCount.get() > 0 ? 
                        (double) cacheHitCount.get() / (cacheHitCount.get() + cacheMissCount.get()) : 0.0)
                .build();
    }

    /**
     * 重置统计信息
     */
    public void resetStatistics() {
        cacheHitCount.set(0);
        cacheMissCount.set(0);
        log.info("缓存统计信息已重置");
    }

    /**
     * 用户信息实体
     */
    @lombok.Data
    @lombok.Builder
    public static class UserInfo {
        private Long id;
        private String name;
        private String email;
        private String phone;
    }

    /**
     * 缓存统计信息
     */
    @lombok.Data
    @lombok.Builder
    public static class CacheStatistics {
        private long hitCount;
        private long missCount;
        private long totalCount;
        private double hitRatio;
    }
}
